package gaml.text.parser;

import gaml.error.GamlException;
import gaml.text.TextNodeBridge;
import gaml.text.YamlParserStore;
import gaml.text.YamlText;
import gaml.text.YamlTextParser;
import gaml.yaml.MappingNode;
import gaml.yaml.YamlNode;
import gaml.yaml.ahchor.YamlAnchorCodeStore;

/**
 * parse mapping node from it's text representation
 * @author shnireck
 *
 */
public class MappingNodeParser implements YamlTextParser {
	static final String incorrectMapLineFormat = "Mailformed mapping node line [%s] (line num %d)";
	static final String incorrectMapValueFormat = "Mailformed mapping value [%s]";
	static final String noMappingValue = "Document end reached, but no value for mapping found!";
	
	YamlParserStore store = null;
	YamlAnchorCodeStore anchors = null;
	
	/**
	 * new mapping parser requires configuration object and parsers store
	 * @param config configuration
	 * @param store yaml parsers store
	 */
	public MappingNodeParser (YamlAnchorCodeStore anchors, YamlParserStore store) {
		this.store = store;
		this.anchors = anchors;
	}
	
	@Override
	public boolean isParserFor (YamlText text) throws GamlException {  return "{".equals (text.getValue ()); }
	
	@Override
	public String getParsingTail (YamlText text) throws GamlException { return text.getValue ().substring (1).trim (); }
	
	/**
	 * get string tail from parsing mapping value node
	 * @param text yaml text to parse
	 * @return string value for parsing tail
	 * @throws GamlException
	 */
	public String getValueParsingTail (YamlText text) throws GamlException {
		if (! text.getValue ().startsWith (":")) throw new GamlException (String.format (incorrectMapValueFormat, text.getValue ()));
		return text.getValue ().substring (1).trim ();
	}
	
	@Override
	public YamlNode parseText (YamlText text, YamlNode parent) throws GamlException {
		MappingNode node = (MappingNode) new MappingNode (parent).setTag (text.getTag ());
		node.setAnchor (anchors.getAnchor (text.getLine ().getAnchor (), node));
		text.next ();

		while (! text.isEnd ()) {
			if ("}".equals (text.getLine ().getValue ())) { text.next (); break; }
			else if (text.getIdentation () < (node.getLevel () + 1)) break;
			else if (isMappingKey (text))
				node.addChild (
						new TextNodeBridge (text.setTail (getParsingTail (text)), node).parseText (store).getNode (),
						new TextNodeBridge (text.setTail (getValueParsingTail (text)), node).parseText (store).getNode ());
			else throw new GamlException (String.format (incorrectMapLineFormat, text.getValue (), text.getCurrent ()));
		}
		
		return node;
	}
	
	protected static boolean isMappingKey (YamlText text) throws GamlException {
		while (text.getValue ().isEmpty () && (! text.isEnd ())) text.next ();

		return (! text.isEnd () && (text.getValue ().startsWith ("?")));
	}
}